package sailhero

import (
	"errors"
	"github.com/wsw188440873/ctrl-cali/types"
	"iot-base/common/ctrltype"
	"iot-base/common/logger"
	"iot-base/common/notify"
	"regexp"
	"strconv"
	"time"
)

type CalibratorLogic struct {
	requestId string
	stationId string
	thingId   string //设备ID
	caliId    string //校准仪ID

}

func NewCalibratorLogic(stationId, thingId, caliId, requestId string) *CalibratorLogic {
	return &CalibratorLogic{
		requestId: requestId,
		stationId: stationId,
		thingId:   thingId,
		caliId:    caliId,
	}
}

// Zero 零气校准 start.
func (l *CalibratorLogic) Zero(modelId string, flow int) (int, error) {
	////todo test
	//return types.Success, nil
	var err error
	//设备ID
	thingId := l.thingId
	//校准仪
	caliId := l.caliId
	// 获取校准仪的状态.
	caloStatus, err := GetThingRealTimeStatus(l.caliId)
	errorCode := getStatusErr(caloStatus)
	logger.SLog.Infof("[%v][Zero 校准仪] modelId = [%v] thingId = [%v] result = [%v] errorCode:=%v", l.requestId, modelId, caliId, caloStatus, errorCode)
	if errorCode != types.Success {
		var msg string
		if err != nil {
			msg = err.Error()
		}
		return errorCode, errors.New("获取校准仪状态错误:" + msg)
	}
	// 获取设备状态.
	gasStatus, err := GetThingRealTimeStatus(thingId)
	errorCode = getStatusErr(gasStatus)
	logger.SLog.Infof("[%v][Zero 设备] modelId = [%v] thingId = [%v] result = [%v] errorCode:=%v", l.requestId, modelId, thingId, gasStatus, errorCode)
	if errorCode != types.Success {
		var msg string
		if err != nil {
			msg = err.Error()
		}
		return errorCode, errors.New("获取设备状态错误" + msg)
	}
	// 校准仪发送零气校准,
	respStatus, err := l.CaliZeroCmd(caliId, flow)
	if respStatus != types.Success {
		return respStatus, err
	}
	// 设备零气校准.
	respStatus, err = l.ThingZeroCmd(thingId, modelId)
	if respStatus != types.Success {
		logger.SLog.Errorf("[%v][ThingZeroCmd] [校准失败] modelId = [%v] thingId = [%v] errorCode:=%v", l.requestId, modelId, thingId, respStatus)
		// 校准失败给校准仪发送结束命令.
		code, err := l.CancelCaliZero(caliId)
		if code != types.Success {
			code, err = l.CancelCaliZero(caliId)
			return code, err
		}
	}
	return types.Success, err
}
func (l *CalibratorLogic) CancelZero(modelId string) (int, error) {
	//设备ID
	thingId := l.thingId
	//校准仪
	caliId := l.caliId
	// 状态是否校准中
	//gasStatus := GetThingRealTimeStatus(modelId,thingId)
	//if gasStatus == 2 {
	//
	//}
	errCode, err := l.CancelThingZero(thingId, modelId)
	if errCode != types.Success {
		logger.SLog.Errorf("[%v][CancelZero] [发送取消失败] modelId = [%v] thingId = [%v] errorCode:=%v", l.requestId, modelId, thingId, errCode)
		errCode, err = l.CancelThingZero(thingId, modelId)
		if errCode != types.Success {
			return errCode, err
		}
	}
	// 状态是否校准中
	//caloStatus := GetThingRealTimeStatus(types.CaloModelId,l.caliId)
	//if caloStatus == 2 {
	//}

	errCode, err = l.CancelCaliZero(caliId)
	if errCode != types.Success {
		errCode, err = l.CancelCaliZero(caliId)
		if errCode != types.Success {
			return errCode, err
		}
	}
	return types.Success, err
}
func (l *CalibratorLogic) ConfirmZero(modelId string) (int, error) {
	thingId := l.thingId
	//校准仪
	caliId := l.caliId
	// 状态是否校准中
	gasStatus, err := GetThingRealTimeStatus(thingId)
	logger.SLog.Infof("[%v][ConfirmZero 设备状态] modelId = [%v] thingId = [%v] gasStatus = [%v]", l.requestId, modelId, thingId, gasStatus)
	if gasStatus == 2 {
		errCode, err := l.ConfirmThingZero(thingId, modelId)
		if errCode != types.Success {
			logger.SLog.Errorf("[%v][ConfirmThingZero 提交设备确认] modelId = [%v] thingId = [%v] gasStatus = [%v]", l.requestId, modelId, thingId, gasStatus)
			errCode, err = l.ConfirmThingZero(thingId, modelId)
			if errCode != types.Success {
				return errCode, err
			}
		}
	}
	// 状态是否校准中
	//caloStatus := GetThingRealTimeStatus(types.CaloModelId,l.caliId)
	//if caloStatus == 2 {
	//}
	errCode, err := l.CancelCaliZero(caliId)
	if errCode != types.Success {
		logger.SLog.Errorf("[%v][CancelCaliZero 取消校准仪] modelId = [%v] thingId = [%v] gasStatus = [%v]", l.requestId, modelId, thingId, gasStatus)
		errCode, err = l.CancelCaliZero(caliId)
		if errCode != types.Success {
			return errCode, err
		}
	}
	return types.Success, err
}

// CaliZeroCmd 校准仪（零气校准）.
func (l *CalibratorLogic) CaliZeroCmd(thingId string, flow int) (int, error) {
	var err error
	// (校准仪)发送零气.
	cal := &ctrltype.CtrlCmd{
		ID:      types.CalibratorZero[types.Start],
		ThingID: thingId,
		Params: map[string]interface{}{
			"flow": strconv.Itoa(flow),
		},
	}
	logger.SLog.Infof("[%v] CaliZeroCmd send = [%v] ", l.requestId, cal)
	result, err := CtrlResp(cal)
	logger.SLog.Infof("[%v] CaliZeroCmd result = [%v] err:=%v", l.requestId, result, err)
	if err != nil {
		return types.CalibratorNewsletterErr, err
	}
	if value, ok := result["msg"]; ok {
		if value.(string) != "ok" {
			return types.CalibratorSendCommandErr, err
		}
	} else {
		return types.CalibratorSendCommandErr, err
	}
	return types.Success, err
}

// CancelCaliZero 取消校准仪零气校准.
func (l *CalibratorLogic) CancelCaliZero(thingId string) (int, error) {
	var err error
	cal := &ctrltype.CtrlCmd{
		ID:      types.CalibratorZero[types.End],
		ThingID: thingId,
	}
	logger.SLog.Infof("[%v] CancelCaliZero send = [%v] ", l.requestId, cal)
	result, err := CtrlResp(cal)
	logger.SLog.Infof("[%v] CancelCaliZero result = [%v] err:=%v", l.requestId, result, err)
	if err != nil {
		return types.CalibratorNewsletterErr, err
	}
	if value, ok := result["msg"]; ok {
		if value.(string) != "ok" {
			return types.CalibratorSendCommandErr, err
		}
	} else {
		return types.CalibratorSendCommandErr, err
	}
	return types.Success, nil
}

// ThingZeroCmd 设备零气校准.
func (l *CalibratorLogic) ThingZeroCmd(thingId string, modelId string) (int, error) {
	var err error
	// 发送仪器校准命令
	ins := &ctrltype.CtrlCmd{
		ID:      types.GasCalibratorZero[modelId][types.Start],
		ThingID: thingId,
	}
	logger.SLog.Infof("[%v] ThingZeroCmd send = [%v] ", l.requestId, ins)
	result, err := CtrlResp(ins)
	logger.SLog.Infof("[%v] ThingZeroCmd result = [%v] err:=%v", l.requestId, result, err)
	if err != nil {
		return types.InstrumentNewsletterErr, err
	}
	if value, ok := result["msg"]; ok {
		if value.(string) != "ok" {
			return types.InstrumentSendCommandError, err
		}
	} else {
		return types.InstrumentSendCommandError, err
	}
	return types.Success, err
}

// ConfirmThingZero 确认零气校准.
func (l *CalibratorLogic) ConfirmThingZero(thingId string, modelId string) (int, error) {
	var err error
	// 发送仪器校准命令
	ins := &ctrltype.CtrlCmd{
		ID:      types.GasCalibratorZero[modelId][types.Confirm],
		ThingID: thingId,
	}

	logger.SLog.Infof("[%v] ThingZero send = [%v] ", l.requestId, ins)
	result, err := CtrlResp(ins)
	logger.SLog.Infof("[%v] ThingZero result = [%v] err:=%v", l.requestId, result, err)
	if err != nil {
		return types.InstrumentNewsletterErr, err
	}
	if value, ok := result["msg"]; ok {
		if value.(string) != "ok" {
			return types.InstrumentSendCommandError, err
		}
	} else {
		return types.InstrumentSendCommandError, err
	}
	return types.Success, err
}

// CancelThingZero 取消设备仪器校准.
func (l *CalibratorLogic) CancelThingZero(thingId string, modelId string) (int, error) {
	// 发送仪器校准命令
	ins := &ctrltype.CtrlCmd{
		ID:      types.GasCalibratorZero[modelId][types.End],
		ThingID: thingId,
	}
	logger.SLog.Infof("[%v] CancelThingZero send = [%v] ", l.requestId, ins)
	result, err := CtrlResp(ins)
	logger.SLog.Infof("[%v] CancelThingZero result = [%v] err:=%v", l.requestId, result, err)
	if err != nil {
		return types.InstrumentNewsletterErr, err
	}
	if value, ok := result["msg"]; ok {
		if value.(string) != "ok" {
			return types.InstrumentSendCommandError, err
		}
	} else {
		return types.InstrumentSendCommandError, err
	}
	return types.Success, nil
}

// Zero 零气校准 end.

// Span 跨度校准 start
func (l *CalibratorLogic) Span(modelId string, number int, units string, caliFlow int) (int, error) {
	thingId := l.thingId
	//校准仪
	caliId := l.caliId

	// 获取校准仪的状态.
	caloStatus, err := GetThingRealTimeStatus(l.caliId)
	errorCode := getStatusErr(caloStatus)
	if errorCode != types.Success {
		logger.SLog.Infof("[%v] m_calo status = [%v] err:=%v", l.requestId, errorCode, errorCode)
		return errorCode, err
	}
	// 获取设备状态.
	gasStatus, err := GetThingRealTimeStatus(thingId)
	errorCode = getStatusErr(gasStatus)
	if errorCode != types.Success {
		logger.SLog.Infof("[%v] Thing status = [%v] err:=%v", l.requestId, gasStatus, errorCode)
		return errorCode, err
	}
	// 校准仪 ,( todo 这里需要设备的物模型ID )
	code, err := l.CaliSpanCmd(caliId, modelId, units, number, caliFlow)
	if code != types.Success {
		return code, err
	}
	// 设备
	code, err = l.ThingSpanCmd(thingId, modelId, number)
	if code != types.Success {
		code, err = l.CancelCaliSpan(caliId)
		if code != types.Success {
			return l.CancelCaliSpan(caliId)
		}
	}
	return types.Success, err
}
func (l *CalibratorLogic) CancelSpan(modelId string, number int) (int, error) {
	thingId := l.thingId
	//校准仪
	caliId := l.caliId
	// 状态是否校准中
	//gasStatus := GetThingRealTimeStatus(modelId,thingId)
	//if gasStatus == 2 {
	//
	//}
	errCode, err := l.CancelThingSpan(thingId, modelId, number)
	if errCode != types.Success {
		errCode, err = l.CancelThingSpan(thingId, modelId, number)
		if errCode != types.Success {
			return errCode, err
		}
	}

	// 状态是否校准中
	//caloStatus := GetThingRealTimeStatus(types.CaloModelId,l.caliId)
	//if caloStatus == 2 {
	//
	//}
	errCode, err = l.CancelCaliSpan(caliId)
	if errCode != types.Success {
		errCode, err = l.CancelCaliSpan(caliId)
		if errCode != types.Success {
			return errCode, err
		}
	}
	return types.Success, err
}
func (l *CalibratorLogic) ConfirmSpan(modelId string, number int) (int, error) {
	////TODO test
	//return types.Success, nil

	thingId := l.thingId
	//校准仪
	caliId := l.caliId
	// 状态是否校准中
	gasStatus, err := GetThingRealTimeStatus(thingId)
	if gasStatus == 2 {
		errCode := l.ConfirmThingSpan(thingId, modelId, number)
		if errCode != types.Success {
			errCode = l.ConfirmThingSpan(thingId, modelId, number)
			if errCode != types.Success {
				return errCode, err
			}
		}
	}
	// 状态是否校准中
	//caloStatus := GetThingRealTimeStatus(types.CaloModelId,l.caliId)
	//if caloStatus == 2 {
	//
	//}
	errCode, err := l.CancelCaliSpan(caliId)
	if errCode != types.Success {
		errCode, err = l.CancelCaliSpan(caliId)
		if errCode != types.Success {
			return errCode, err
		}
	}
	return types.Success, err
}

//CaliSpanCmd 校准仪（跨度校准）.
func (l *CalibratorLogic) CaliSpanCmd(thingId string, modelId string, units string, number int, caliFlow int) (int, error) {
	// 发送仪器校准命令
	//todo 溶度和流量
	ins := &ctrltype.CtrlCmd{
		ID:      types.CalibratorSpan[types.Start],
		ThingID: thingId,
		Params: map[string]interface{}{
			"flow":          strconv.Itoa(caliFlow),
			"units":         units, // nmol/mol, μmol/mol
			"type":          types.CalibratorType[modelId],
			"concentration": strconv.Itoa(number),
		},
	}
	logger.SLog.Infof("[%v] CaliSpanCmd send = [%v] ", l.requestId, ins)
	result, err := CtrlResp(ins)
	logger.SLog.Infof("[%v] CaliSpanCmd result = [%v] err:=%v", l.requestId, result, err)
	if err != nil {
		return types.CalibratorNewsletterErr, err
	}
	if value, ok := result["msg"]; ok {
		if value.(string) != "ok" {
			return types.CalibratorSendCommandErr, err
		}
	} else {
		return types.CalibratorSendCommandErr, err
	}
	return types.Success, err
}
func (l *CalibratorLogic) ThingSpanCmd(thingId string, modelId string, number int) (int, error) {
	// 发送仪器校准命令
	ins := &ctrltype.CtrlCmd{
		ID:      types.GasCalibratorSpan[modelId][types.Start],
		ThingID: thingId,
		Params: map[string]interface{}{
			"concentration": strconv.Itoa(number),
		},
	}
	logger.SLog.Infof("[%v] ThingSpanCmd send = [%v] ", l.requestId, ins)
	result, err := CtrlResp(ins)
	logger.SLog.Infof("[%v] ThingSpanCmd result = [%v] err:=%v", l.requestId, result, err)
	if err != nil {
		return types.InstrumentNewsletterErr, err
	}
	if value, ok := result["msg"]; ok {
		if value.(string) != "ok" {
			return types.InstrumentSendCommandError, err
		}
	} else {
		return types.InstrumentSendCommandError, err
	}
	return types.Success, err
}
func (l *CalibratorLogic) CancelCaliSpan(thingId string) (int, error) {
	ins := &ctrltype.CtrlCmd{
		ID:      types.CalibratorSpan[types.End],
		ThingID: thingId,
	}
	logger.SLog.Infof("[%v] CancelCali send = [%v] ", l.requestId, ins)
	result, err := CtrlResp(ins)
	logger.SLog.Infof("[%v] CancelCali result = [%v] err:=%v", l.requestId, result, err)
	if err != nil {
		return types.CalibratorNewsletterErr, err
	}
	if value, ok := result["msg"]; ok {
		if value.(string) != "ok" {
			return types.CalibratorSendCommandErr, err
		}
	} else {
		return types.CalibratorSendCommandErr, err
	}
	return types.Success, err
}
func (l *CalibratorLogic) CancelThingSpan(thingId string, modelId string, number int) (int, error) {
	ins := &ctrltype.CtrlCmd{
		ID:      types.GasCalibratorSpan[modelId][types.End],
		ThingID: thingId,
		Params: map[string]interface{}{
			"concentration": strconv.Itoa(number),
		},
	}
	logger.SLog.Infof("[%v] CancelCali send = [%v] ", l.requestId, ins)
	result, err := CtrlResp(ins)
	logger.SLog.Infof("[%v] CancelCali  result = [%v] err:=%v", l.requestId, result, err)
	if err != nil {
		return types.InstrumentNewsletterErr, err
	}
	if value, ok := result["msg"]; ok {
		if value.(string) != "ok" {
			return types.InstrumentSendCommandError, err
		}
	} else {
		return types.InstrumentSendCommandError, err
	}
	return types.Success, err
}
func (l *CalibratorLogic) ConfirmThingSpan(thingId string, modelId string, number int) int {
	ins := &ctrltype.CtrlCmd{
		ID:      types.GasCalibratorSpan[modelId][types.Confirm],
		ThingID: thingId,
		Params: map[string]interface{}{
			"concentration": strconv.Itoa(number),
		},
	}
	logger.SLog.Infof("[%v] CancelCali send = [%v] ", l.requestId, ins)
	result, err := CtrlResp(ins)
	logger.SLog.Infof("[%v] CancelCali result = [%v] err:=%v", l.requestId, result, err)
	if err != nil {
		return types.InstrumentNewsletterErr
	}
	if value, ok := result["msg"]; ok {
		if value.(string) != "ok" {
			return types.InstrumentSendCommandError
		}
	} else {
		return types.InstrumentSendCommandError
	}
	return types.Success
}

// Span 跨度校准 end

//StartCaliTask 开始任务.
func (l *CalibratorLogic) StartCaliTask(gasType int, stationId string, modelId string, num int, units string, caliFlow int) (int, error) {
	if gasType == 0 {
		return l.Zero(modelId, caliFlow)
	} else {
		return l.Span(modelId, num, units, caliFlow)
	}
}
func (l *CalibratorLogic) GetValue() (string, error) {
	////todo test
	//return strconv.Itoa(rand.Intn(100) + 1), nil
	thingId := l.thingId

	ins := &ctrltype.CtrlCmd{
		ID:      "value",
		ThingID: thingId,
	}

	logger.SLog.Infof("[%v] GetValue send = [%v] ", l.requestId, ins)
	result, err := CtrlResp(ins)
	logger.SLog.Infof("[%v] GetValue result = [%v] err:=%v", l.requestId, result, err)
	if err != nil {
		return "", err
	}

	// todo 注意，这里可能需要判断一下设备状态.
	if value, ok := result["value"]; ok {
		if value.(string) != "ok" {
			reg := regexp.MustCompile("[\\-]?[\\d]+\\.?[\\d]+")
			data := reg.Find([]byte(value.(string)))
			return string(data), nil
		}
	} else {
		return "", errors.New("获取参数失败")
	}
	return "", errors.New("获取参数失败")
}

// EndCaliTask 结束任务.
func (l *CalibratorLogic) EndCaliTask(gasType int, stationId string, modelId string, num int) (int, error) {
	if gasType == 0 {
		return l.CancelZero(modelId)
	} else {
		return l.CancelSpan(modelId, num)
	}
}

// ConfirmCali 确认校准.
func (l *CalibratorLogic) ConfirmCali(gasType int, stationId string, modelId string, num int) (int, error) {
	if gasType == 0 {
		return l.ConfirmZero(modelId)
	} else {
		return l.ConfirmSpan(modelId, num)
	}
}
func CtrlResp(cmd *ctrltype.CtrlCmd) (map[string]interface{}, error) {
	logger.SLog.Infof("calibrator CtrlResp cmd %v", cmd)
	var pResult *ctrltype.CtrlResult
	notify.Ctrl(cmd, 3*time.Second, func(pReply *ctrltype.CtrlResult) {
		pResult = pReply

	}, true)
	if pResult == nil {
		return nil, nil
	}
	if pResult.Error != nil && pResult.Error.Error() == "time out" {
		logger.SLog.Error("calibrator CtrlResp", "cmd", cmd, "result", pResult.Error)
		return nil, errors.New("time out")
	}
	if pResult.Error != nil {
		logger.SLog.Error("calibrator CtrlResp", "cmd", cmd, "result", pResult.Error)
		return nil, pResult.Error
	}
	return pResult.Result, nil
}

//GetThingRealTimeStatus 查询设备状态
func GetThingRealTimeStatus(thingId string) (int, error) {
	// 查询状态.
	cmd := &ctrltype.CtrlCmd{
		ID:      types.Status,
		ThingID: thingId,
	}
	result, err := CtrlResp(cmd)
	logger.SLog.Infof("[GetThingRealTimeStatus] thingId = [%v] result = [%v] err:=%v", thingId, result, err)
	if err != nil {
		return 0, err
	}
	if value, ok := result["msg"]; ok {
		v, _ := strconv.Atoi(value.(string))
		return v, err
	} else {
		return 0, errors.New("获取返回消息失败")
	}
}
func getStatusErr(status int) int {
	switch status {
	case 0:
		return types.NetworkAnomaly
	case 1, 2:
		return types.Success
	//case 2:
	//	// 校准状态可以发送命令.
	//	return types.CalibratorStatusError
	case 3:
		return types.CalibratorStatusBootUp
	}
	return types.DeviceStatusIsAbnormal
}
